package com.oracle.news.service.impl;

import com.alibaba.dubbo.config.annotation.Service;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.oracle.mapper.NewsMapper;
import com.oracle.news.service.api.NewsServiceApi;
import com.oracle.pojo.News;
import com.oracle.pojo.NewsExample;
import com.oracle.vo.NewsSearch;
import com.oracle.vo.PageVo;
import com.oracle.vo.ResultEntity;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class NewsServiceImpl implements NewsServiceApi {

    @Autowired
    private NewsMapper newsMapper;

    //redis
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Value("${cache_key_prefix}")
    private String cacheKeyPrefix;

    //RabbitMQ
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Value("${es_exchange}")
    private String es_exchange;
    @Value("${es_queue}")
    private String es_queue;
    @Value("${es_bindKey}")
    private String es_bindKey;

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public ResultEntity addNews(News news) {
        news.setCreatedate(new Timestamp(new Date().getTime()));
        news.setModifydate(new Timestamp(new Date().getTime()));
        news.setStatus(0);
        //添加新闻信息，返回主键
        this.newsMapper.insertSelective(news);
        //把新闻数据发送到MQ队列中，异步进行ES数据索引添加
        News toEsNews = new News();
        toEsNews.setTitle(news.getTitle());
        toEsNews.setAuthor(news.getAuthor());
        toEsNews.setCategory(news.getCategory());
        toEsNews.setImage(news.getImage());
        toEsNews.setId(news.getId());
        System.out.println("toEsNews---------->"+toEsNews);
        this.rabbitTemplate.convertAndSend(es_exchange,es_bindKey,toEsNews);
        //判断是否是置顶的新闻，如果是缓存redis
        if (news.getIstop() != null && news.getIstop() == 1) {
            //使用list缓存  key----->news-project:news:top
            String cacheKey = cacheKeyPrefix + "news:top";
            News cacheNews = new News();
            cacheNews.setId(news.getId());
            cacheNews.setAuthor(news.getAuthor());
            cacheNews.setCategory(news.getCategory());
            cacheNews.setImage(news.getImage());
            cacheNews.setTitle(news.getTitle());
            String cacheJson = JSONObject.toJSONString(cacheNews);
            redisTemplate.boundListOps(cacheKey).leftPush(cacheJson);
        }
        return new ResultEntity(ResultEntity.CODE_SUCCESS, ResultEntity.MSG_SUCCESS);
    }

    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
    @Override
    public PageVo<News> getNewsBySearch(Integer pageIndex, Integer pageSize, NewsSearch ns) {
        //使用分页插件
        Page page = PageHelper.startPage(pageIndex, pageSize);
        //判断条件
        NewsExample example = null;
        if (ns != null) {
            //获取模板条件
            example = new NewsExample();
            NewsExample.Criteria criteria = example.createCriteria();
            //(标题(模糊查询)
            if (ns.getTitle() != null && !"".equals(ns.getTitle())) {
                criteria.andTitleLike("%" + ns.getTitle() + "%");
            }
            //作者来源
            if (ns.getAuthor() != null && !"".equals(ns.getAuthor())) {
                criteria.andAuthorEqualTo(ns.getAuthor());
            }
            // 二级类型
            if (ns.getCategory() != null && !"".equals(ns.getCategory())) {
                criteria.andCategoryEqualTo(ns.getCategory());
            }
            // 时间范围
            if (ns.getMinTime() != null && !"".equals(ns.getMinTime())) {
                criteria.andCreatedateGreaterThanOrEqualTo(ns.getMinTime());
            }
            if (ns.getMaxTime() != null && !"".equals(ns.getMaxTime())) {
                criteria.andCreatedateLessThanOrEqualTo(ns.getMaxTime());
            }
            // 新闻状态
            if (ns.getStatus() != null) {
                criteria.andStatusEqualTo(ns.getStatus());
            }
        }
        //执行查询数据库
        this.newsMapper.selectByExample(example);
        //创建PageVo数据传输对象
        PageVo<News> pageVo = new PageVo<News>();
        Integer total = Integer.parseInt(page.getTotal() + "");
        pageVo.setDataTotal(total);
        pageVo.setObjList(page.getResult());
        pageVo.setPageIndex(page.getPageNum());
        pageVo.setPageTotal(total % pageSize == 0 ? total / pageSize : total / pageSize + 1);
        pageVo.setpageSize(page.getPageSize());
        return pageVo;
    }

    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
    @Override
    public ResultEntity<News> getNewsInfoById(Integer id) {
        News news = this.newsMapper.selectByPrimaryKey(id);
        return new ResultEntity<News>(ResultEntity.CODE_SUCCESS, ResultEntity.MSG_SUCCESS, news);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public ResultEntity updateNews(News news) {
        //执行修改
        news.setModifydate(new Timestamp(new Date().getTime()));
        this.newsMapper.updateByPrimaryKeySelective(news);
        //判断istop是否是顶置
        if (news.getIstop() == 1) {
            //如果是置顶数据，从Redis中获取数据集合，查询改条新闻的标题、作者、类型是否被修改过
            String cacheKey = cacheKeyPrefix + "news:top";
            List<String> jsonList = redisTemplate.boundListOps(cacheKey).range(0, -1);
            for (int i = 0; i < jsonList.size(); i++) {
                News n = JSONObject.parseObject(jsonList.get(i), News.class);
                if (n.getId().equals(news.getId())) {
                    //[标题数据,作者,类型] 有修改就跟新Redis
                    if (!n.getTitle().equals(news.getTitle()) || !n.getAuthor().equals(news.getAuthor())
                            || !n.getCategory().equals(news.getCategory())) {
                        News cacheNews = new News();
                        cacheNews.setId(news.getId());
                        cacheNews.setAuthor(news.getAuthor());
                        cacheNews.setCategory(news.getCategory());
                        cacheNews.setImage(news.getImage());
                        cacheNews.setTitle(news.getTitle());
                        String cacheJson = JSONObject.toJSONString(cacheNews);
                        //更新缓存数据
                        redisTemplate.boundListOps(cacheKey).set(i, cacheJson);
                        break;
                    }
                }
            }
        }
        return new ResultEntity(ResultEntity.CODE_SUCCESS, ResultEntity.MSG_SUCCESS);
    }

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    @Override
    public ResultEntity deleteNews(Integer id,Integer istop) {
        News news = new News();
        news.setId(id);
        news.setStatus(2);
        news.setModifydate(new Timestamp(new Date().getTime()));
        this.newsMapper.updateByPrimaryKeySelective(news);
        //判断是否是顶置数据
        if (istop==1) {
            String cacheKey = cacheKeyPrefix + "news:top";
            List<String> jsonList = redisTemplate.boundListOps(cacheKey).range(0, -1);
            List<News> newsList = new ArrayList<News>();
            boolean isHas = false;
            for (int i = 0; i < jsonList.size(); i++) {
                News n = JSONObject.parseObject(jsonList.get(i), News.class);
                if(n.getId().equals(id)){
                    //查找到指定的数据，执行删除redis缓存
                    this.redisTemplate.opsForList().remove(cacheKey,i,jsonList.get(i));
                }
            }
        }
        return new ResultEntity(ResultEntity.CODE_SUCCESS, ResultEntity.MSG_SUCCESS);
    }

    @Transactional(propagation = Propagation.REQUIRED,rollbackFor = Exception.class)
    @Override
    public ResultEntity<List<News>> getNewsIdsAndTitle() {
        List<News> ids = this.newsMapper.selectNewsIdsAndTitle();
        return new ResultEntity(ResultEntity.CODE_SUCCESS,ResultEntity.MSG_SUCCESS,ids);
    }
}
